package palms.authserver;

import java.io.IOException;
import java.net.Socket;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SealedObject;
import javax.crypto.spec.SecretKeySpec;

import palms.exceptions.InvalidClassMessage;
import palms.exceptions.InvalidTicketMessage;
import palms.exceptions.InvalidUserMessage;
import palms.messages.TGSClientInfo;
import palms.messages.TGSKeyChain;
import palms.messages.TGSRequest;
import palms.messages.TGSResponse;
import palms.messages.TicketSI;
import palms.messages.TicketSL;
import palms.messages.TicketTGS;
import palms.security.PalmsSecurityManager;


public class KTGSWorker implements Runnable {

	private Socket s;
	private AuthLogic al;
	
	public KTGSWorker(Socket s, AuthLogic al){
		this.s = s;
		this.al = al;
	}
	
	@Override
	public void run() {
		try {
			
			TGSRequest tr = TGSRequest.receiveTroughSocket(s);
			processTGSrequest(tr);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidClassMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidUserMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidTicketMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void processTGSrequest(TGSRequest req) throws InvalidKeyException, NoSuchAlgorithmException, IOException, ClassNotFoundException, IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException{
		
		System.out.println("[KTGS]-->Processing a TGS Request.");
		
		SealedObject sealed_tgsticket = req.getTgsTicket();
		SealedObject sealed_clientinfo = req.getClientInfo();
		SecretKeySpec tgskey = al.getKeyTGS();
		
		TicketTGS tgsticket = (TicketTGS)PalmsSecurityManager.DesealObjectWithK(sealed_tgsticket, tgskey);
		TGSClientInfo clientinfo = (TGSClientInfo) PalmsSecurityManager.DesealObjectWithK(sealed_clientinfo, tgsticket.getSessionKey());

		System.out.println();
		System.out.println("[KTGS]-->Processing TGS Ticket.");
		System.out.println("[KTGS]-->The user \"" + tgsticket.getUsername() + "\" requested a service.");
		System.out.println("[KTGS]-->The ticket expiring date: " + tgsticket.getValidity());
		System.out.println("[KTGS]-->Client/TGS session key: " + PalmsSecurityManager.asHex(tgsticket.getSessionKey().getEncoded()));
		
		System.out.println();
		System.out.println("[KTGS]-->Processing Client Info.");
		System.out.println("[KTGS]-->The user \"" + clientinfo.getUsername() + "\" requested a service.");
		System.out.println("[KTGS]-->Time of the request: " + clientinfo.getTimestamp());
		
		if(verifyTGSTicket(tgsticket, clientinfo)){
			
			SecretKeySpec sisessionkey = PalmsSecurityManager.getSessionKey();
			SecretKeySpec slsessionkey = PalmsSecurityManager.getSessionKey();
			TicketSI ticketsi = new TicketSI(clientinfo.getUsername(), s.getInetAddress().getHostAddress(), Calendar.getInstance().getTimeInMillis() + 300000, sisessionkey);
			TicketSL ticketsl = new TicketSL(al.getSiip(), Calendar.getInstance().getTimeInMillis() + 300000, slsessionkey);
			TGSKeyChain keychain = new TGSKeyChain(sisessionkey, slsessionkey);
			
			SealedObject sealed_ticketsi = PalmsSecurityManager.SealObjectWithK(ticketsi, al.getKeySI());
			SealedObject sealed_ticketsl = PalmsSecurityManager.SealObjectWithK(ticketsl, al.getKeySL());
			SealedObject sealed_keychain = PalmsSecurityManager.SealObjectWithK(keychain, tgsticket.getSessionKey());
			
			TGSResponse response = new TGSResponse(sealed_ticketsi, sealed_ticketsl, sealed_keychain);
			
			System.out.println();
			System.out.println("[KTGS]-->Generated Client/SI session key: " + PalmsSecurityManager.asHex(sisessionkey.getEncoded()));
			System.out.println("[KTGS]-->Generated Client/SL session key: " + PalmsSecurityManager.asHex(slsessionkey.getEncoded()));
			System.out.println();
			System.out.println("[KTGS]-->Sealed SL and SI session keys: " + sealed_keychain);
			System.out.println("[KTGS]-->SI ticket: " + sealed_ticketsi);
			System.out.println("[KTGS]-->SL ticket: " + sealed_ticketsl);
			System.out.println();
			
			System.out.println("[KTGS]-->Sending tickets and keychain.");
			response.sendTroughSocket(s);
		
		}else{
			PalmsSecurityManager.sendError(s, new InvalidTicketMessage());
		}
		
	}
	
	public boolean verifyTGSTicket(TicketTGS ticket, TGSClientInfo clientinfo){
		
		if(al.getUserlist().containsKey(ticket.getUsername()) &&
		   ticket.getUsername().equals(clientinfo.getUsername()) &&
		   ticket.getIp().equals(s.getInetAddress().getHostAddress()) &&
		   ticket.getValidity() > clientinfo.getTimestamp()){
			return true;
		}
		else
			return false;
	}
	
	
}
